#pragma once

#include <cassert>
#include <boost/shared_ptr.hpp>
#include <QObject>
#include <QMap>

namespace util
{
  //
  // util::AbstractCreator
  //

  class ICreator {
  public:
    typedef boost::shared_ptr< ICreator > SP;

  public:
    virtual ~ICreator() {}
    virtual QObject * Make() const = 0;
  };

  //
  // util::ConcreteCreator
  //

  template< class CLASS >
  class SimpleCreator : public virtual ICreator {
  public:
    typedef CLASS TClass;

  public:
    virtual TClass * Make() const
    {
      return new TClass;
    }
  };

  //
  // util::ObjectFactory
  //

  template< class CREATOR_ID >
  class ObjectFactory {
  public:
    typedef CREATOR_ID  TCreatorID;

  public:

    template< class T >
    void Reg(const TCreatorID & ID_)
    {
      assert(mRegistry.find(ID_) == mRegistry.end());

      mRegistry[ID_] = ICreator::SP(new SimpleCreator< T >());
    }
    
    template< class T >
    T *Make(const TCreatorID & ID_) const
    {
      TRegistry::const_iterator it = mRegistry.find(ID_);

      if (it == mRegistry.end())
        return 0;

      return qobject_cast< T * >((*it)->Make());
    }

  private:
    typedef QMap< TCreatorID, ICreator::SP > TRegistry;

    TRegistry mRegistry;
  };
} // namespace util